package com.topone.controller;

import com.topone.Const.Model;
import com.topone.Enum.OrderStatusEnum;
import com.topone.Enum.PayStatusEnum;
import com.topone.Enum.ResultEnum;
import com.topone.Enum.TcUserCouponEnum;
import com.topone.Exception.FanZoneException;
import com.topone.Exception.FanZoneServiceException;
import com.topone.Utils.KeyUntil;
import com.topone.Utils.MathUtil;
import com.topone.Utils.ResultVOUntil;
import com.topone.Utils.ServiceUtils;
import com.topone.Utils.wx.tag.WxTagHandler;
import com.topone.VO.ResultVO;
import com.topone.dataObject.Bussiness;
import com.topone.dataObject.OrderMaster;
import com.topone.dataObject.TcUser;
import com.topone.dataObject.TcUserCoupon;
import com.topone.dto.Pay;
import com.topone.dto.TcUserCouponDTO;
import com.topone.repository.BussinessRepository;
import com.topone.repository.OrderMasterRepository;
import com.topone.repository.TcUserCouponRepository;
import com.topone.service.BaseService;
import com.topone.service.TcUserCouponService;
import com.topone.service.TcUserService;
import com.topone.service.impl.ServiceProvider;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxJsapiSignature;
import me.chanjar.weixin.common.bean.menu.WxMenu;
import me.chanjar.weixin.common.bean.menu.WxMenuRule;
import me.chanjar.weixin.common.exception.WxErrorException;
import me.chanjar.weixin.common.util.RandomUtils;
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import me.chanjar.weixin.mp.bean.result.WxMpUser;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.topone.Utils.wx.tag.WxTagHandler.*;

@CrossOrigin
@RestController
@RequestMapping("/wechat")
@Slf4j
public class WechatPortalController extends BaseController {

    @Autowired
    private WxMpService wxService;
    @Autowired
    private WxTagHandler wxTagHandler;
    @Autowired
    private WxMpMessageRouter router;
    @Autowired
    private TcUserCouponService tcUserCouponService;
    @Autowired
    private BaseService baseService;
    @Autowired
    private BussinessRepository bussinessRepository;
    @Autowired
    private TcUserService tcUserService;
    @Autowired
    private OrderMasterRepository orderMasterRepository;
    @Autowired
    private TcUserCouponRepository tcUserCouponRepository;
    @Autowired
    private WxMpService wxMpService;
    @Autowired
    private ServiceProvider serviceProvider;

    @GetMapping(value = "/portal", produces = "text/plain;charset=utf-8")
    public String authGet(
            @RequestParam(name = "signature", required = false) String signature,
            @RequestParam(name = "timestamp", required = false) String timestamp,
            @RequestParam(name = "nonce", required = false) String nonce,
            @RequestParam(name = "echostr", required = false) String echostr) {

        LOG.info("\n接收到来自微信服务器的认证消息：[{}, {}, {}, {}]", signature, timestamp, nonce, echostr);

        if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
            throw new IllegalArgumentException("请求参数非法，请核实!");
        }

        if (this.wxService.checkSignature(timestamp, nonce, signature)) {
            return echostr;
        }
        return "非法请求";
    }

    @PostMapping(value = "/portal", produces = "application/xml; charset=UTF-8")
    public String post(@RequestBody String requestBody,
                       @RequestParam("signature") String signature,
                       @RequestParam("timestamp") String timestamp,
                       @RequestParam("nonce") String nonce,
                       @RequestParam(name = "encrypt_type", required = false) String encType,
                       @RequestParam(name = "msg_signature", required = false) String msgSignature) {
        LOG.info(
                "\n接收微信请求：[signature=[{}], encType=[{}], msgSignature=[{}],"
                        + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
                signature, encType, msgSignature, timestamp, nonce, requestBody);

        if (!this.wxService.checkSignature(timestamp, nonce, signature)) {
            throw new IllegalArgumentException("非法请求，可能属于伪造的请求！");
        }

        String out = null;
        if (encType == null) {
            // 明文传输的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toXml();
        } else if ("aes".equals(encType)) {
            // aes加密的消息
            WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(
                    requestBody, this.wxService.getWxMpConfigStorage(), timestamp,
                    nonce, msgSignature);
            LOG.debug("\n消息解密后内容为：\n{} ", inMessage.toString());
            WxMpXmlOutMessage outMessage = this.route(inMessage);
            if (outMessage == null) {
                return "";
            }

            out = outMessage.toEncryptedXml(this.wxService.getWxMpConfigStorage());
        }

        LOG.debug("\n组装回复信息：{}", out);

        return out;
    }

    private WxMpXmlOutMessage route(WxMpXmlMessage message) {
        try {
            return this.router.route(message);
        } catch (FanZoneServiceException e) {
            throw e;
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
        }

        return null;
    }

    @RequestMapping(value = "/wechat/menu",
            method = RequestMethod.PUT,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE,
            consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public String updateMenu3(@RequestBody String menuJson) throws WxErrorException {
        LOG.info("Update WX default menu::{}", menuJson);
        wxService.getMenuService().menuDelete();
        wxService.getMenuService().menuCreate(menuJson);
        return "更新成功";
    }

    @RequestMapping(value = "/wechat/menu/get", method = RequestMethod.GET)
    public WxMpMenu selectMenu() throws WxErrorException {
        LOG.info("GET WX customer menu:{}", wxService.getMenuService().menuGet());
        return wxService.getMenuService().menuGet();
    }

    private void createConditionalMenu(String tagName, String who, String menuJson) throws WxErrorException {
        LOG.info("updating menu: {}", who);
        WxMenu wxMenu = WxMenu.fromJson(menuJson);
        Long tagId = wxTagHandler.tagGet(tagName);
        WxMenuRule matchRule = new WxMenuRule();
        matchRule.setTagId(String.valueOf(tagId));
        wxMenu.setMatchRule(matchRule);
        wxService.getMenuService().menuCreate(wxMenu);
    }

    @PostMapping("/create")
    public ResultVO create(@RequestParam("openid") String openid,
                           @RequestParam("bussinessId") String bussinessId,
                           @RequestParam(value = "couponCode", required = false) String couponCode,
                           @RequestParam("amount") String amount) {


        Bussiness bussiness =  bussinessRepository.getOne(bussinessId);
        Map<String, Object> tempMap;
        Double total = Double.valueOf(amount);
        if (StringUtils.isEmpty(couponCode) && StringUtils.isNotEmpty(bussinessId)) {
            //仅仅是用户付款 不使用优惠券
            LOG.info("[用户付款，不使用优惠券]");
            if (Objects.isNull(bussiness)) {
                LOG.error("商家信息不存在-->" + bussinessId);
                return ResultVOUntil.error(1, "商家信息不存在-->" + bussinessId);
            }
            try {
                tempMap = baseService.getPay(null, openid, total, bussiness, Model.Pay_TYPE_ONLY,couponCode);
            } catch (Exception e) {
                LOG.error("【H5调用微信支付】失败 e={}", e.fillInStackTrace());
                return ResultVOUntil.error(1, ResultEnum.ORDER_CREATE_ERROR.getMessage());
            }
            LOG.info("预付单信息，{}", tempMap);
            return ResultVOUntil.success(tempMap);
        }
        // 1.查询用户优惠券
        TcUserCouponDTO tcUserCoupon = tcUserCouponService.findByCouponCode(couponCode);
        if (tcUserCoupon.getCouponNum() != null && tcUserCoupon.getCouponNum() > 0) {
            DateFormat df = new SimpleDateFormat("HH:mm:ss");
            try {
                String now = df.format(new Date());
                Date nowTime = df.parse(now);
                if ((tcUserCoupon.getDurationStartTime() == null
                        && tcUserCoupon.getDurationEndTime() == null)
                        || (tcUserCoupon.getDurationStartTime().getTime() - nowTime.getTime() < 0
                        && tcUserCoupon.getDurationEndTime().getTime() - nowTime.getTime() > 0)) {
                    if (MathUtil.compareTo(Double.valueOf(amount), tcUserCoupon.getLowestConsume().doubleValue())) {

                        //优惠后的价格
                        total -= tcUserCoupon.getDiscountPrice().doubleValue();
                        log.info("----total-----{}",total);
                        if(total<0.01){
                            TcUser tcUser=tcUserService.findByopenid(openid);
                            if(Objects.isNull(tcUser)){
                                return ResultVOUntil.error(1,"用户不存在");
                            }
                            OrderMaster orderMaster=new OrderMaster();
                            orderMaster.setOrderId(KeyUntil.getUniqueKey());
                            orderMaster.setOrderStatus(OrderStatusEnum.FINISH.getCode());
                            orderMaster.setBuyerOpenid(openid);
                            orderMaster.setOrderAmount(new BigDecimal(total));
                            orderMaster.setBuyerPhone(tcUser.getHandPhone());
                            orderMaster.setBuyerName(tcUser.getUserName());
                            orderMaster.setPayStatus(PayStatusEnum.SUCCESS.getCode());
                            orderMasterRepository.save(orderMaster);
                            TcUserCouponDTO tcUserCouponDTO=tcUserCouponService.findByCouponCode(couponCode);
                            if(Objects.isNull(tcUserCouponDTO) &&
                                    tcUserCouponDTO.getUseStatus()!=TcUserCouponEnum.UNUSE.getCode()){
                                return  ResultVOUntil.error(1,"用户优惠券不存在或者优惠券状态不正确");
                            }
                            tcUserCouponDTO.setUseStatus(TcUserCouponEnum.USED.getCode());
                            TcUserCoupon tcUserCoupon1=new TcUserCoupon();
                            BeanUtils.copyProperties(tcUserCouponDTO,tcUserCoupon1);
                            log.info("------tcusercoupon1----{}",tcUserCoupon1);
                            tcUserCouponRepository.save(tcUserCoupon1);
                            return ResultVOUntil.success("支付成功");
                        }else {
                            try {
                                //下单并支付
                                tempMap = baseService.getPay(amount, openid, total, bussiness, Model.PAY_TYPE_SCAN, couponCode);
                            } catch (FanZoneException e) {
                                LOG.error("【H5调用微信支付】失败 e={}", e.fillInStackTrace());
                                return ResultVOUntil.error(1, ResultEnum.ORDER_CREATE_ERROR.getMessage());
                            }
                            LOG.info("预付单信息，{}", tempMap);
                            return ResultVOUntil.success(tempMap);
                        }
                    } else {
                        LOG.error("未达到最低消费,无法使用优惠券");
                        return ResultVOUntil.error(1, "未达到最低消费,无法使用优惠券");
                    }
                } else {
                    LOG.error("该时段无法使用优惠券");
                    return ResultVOUntil.error(1, "该时段无法使用优惠券");
                }
            } catch (Exception e) {
                LOG.error("扫码核销券失败", e.fillInStackTrace());
                return ResultVOUntil.error(1, e.fillInStackTrace().toString());
            }
        } else {
            return ResultVOUntil.error(1, "用户无可用优惠券");
        }
    }

    @GetMapping("/share")
    public ResultVO createJsapiSignture(@RequestParam("url") String url){
        try {
            WxJsapiSignature wxJsapiSignature=wxService.createJsapiSignature(url);
            LOG.info("生成分享签名成功-->",wxJsapiSignature);
            return ResultVOUntil.success(wxJsapiSignature);
        }catch (Exception e){
            LOG.error("生成分享签名失败-->",e.fillInStackTrace());
            return ResultVOUntil.error(1,e.getMessage());
        }
    }

    @GetMapping("/jsapiTicket")
    public ResultVO getJsapiticket(){
        try{
            Map<String,Object> map=new HashMap<>();
            String jsapiTicket=wxService.getJsapiTicket();
            String noncestr = RandomUtils.getRandomStr();
            long timestamp = System.currentTimeMillis() / 1000L;
            map.put("noncestr",noncestr);
            map.put("timestamp",timestamp);
            map.put("jsapiTicket",jsapiTicket);
            return ResultVOUntil.success(map);
        }catch (Exception e){
            LOG.error("获取jsapiTicket失败",e.fillInStackTrace());
            return  ResultVOUntil.error(1,"获取jsapiTicket失败-->"+e.getMessage());
        }
    }

    @RequestMapping(value = "/xtoken",
            method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResultVO generateXToken(@RequestParam("code") String code) {
        if (StringUtils.isNotEmpty(code)) {
            try {
                WxMpOAuth2AccessToken accessToken =wxMpService.oauth2getAccessToken(code);
                WxMpUser wxMpUser=wxMpService.oauth2getUserInfo(accessToken,"zh_CN");
                TcUser tcUser=tcUserService.saveUser(wxMpUser);
                return ResultVOUntil.success(tcUser);
            } catch (WxErrorException e) {
                return ResultVOUntil.error(1, e.getError().getErrorMsg());
            }
        } else {
            LOG.error("invalid code...");
            return ResultVOUntil.error(1, "code is null");
        }
    }

    @RequestMapping(value = "/wechat/providerPay", method = RequestMethod.GET)
    public Map<String, String> providerPay(@RequestParam(value = "openid",required = false)  String openid ) {
        LOG.info("-------start----------{}",openid);
        Pay pay = new Pay();
        pay.setOrderId(RandomUtils.getRandomStr());
        pay.setPrice("0.01");
        pay.setSubAppId("wx7c48a2b20c836127");
        pay.setSubMchId("1514046441");
        LOG.info("-----pay info-----:{}", ServiceUtils.toJson(pay));
        return serviceProvider.WxPayService(pay, openid);
    }

    @RequestMapping(value = "/qrcode", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public ResultVO<String> payQrcode(@RequestParam String url) throws WxErrorException {
        WxMpQrCodeTicket ticket = wxService.getQrcodeService().qrCodeCreateLastTicket(url);
        String result=wxService.getQrcodeService().qrCodePictureUrl(ticket.getTicket());
        return ResultVOUntil.success(result);
    }

}
